using System;
using UnityEngine;

namespace DanielSig.UnityExtensions
{
	public static class XRect
	{
		#region SCALING
		
		public static Rect Scale(this Rect rect, Vector2 scalePosition, Vector2 scaleSize)
		{
			return new Rect(rect.x * scalePosition.x, rect.y * scalePosition.y, rect.width * scaleSize.x, rect.height * scaleSize.y);
		}
		
		public static Rect Scale(this Rect rect, float scalar)
		{
			return new Rect(rect.x * scalar, rect.y * scalar, rect.width * scalar, rect.height * scalar);
		}
		public static Rect ScaleSize(this Rect rect, float scalar)
		{
			return new Rect(rect.x, rect.y, rect.width * scalar, rect.height * scalar);
		}
		public static Rect ScalePosition(this Rect rect, float scalar)
		{
			return new Rect(rect.x * scalar, rect.y * scalar, rect.width, rect.height);
		}
		
		public static Rect Scale(this Rect rect, Vector2 scalar)
		{
			return new Rect(rect.x * scalar.x, rect.y * scalar.y, rect.width * scalar.x, rect.height * scalar.y);
		}
		public static Rect ScaleSize(this Rect rect, Vector2 scalar)
		{
			return new Rect(rect.x, rect.y, rect.width * scalar.x, rect.height * scalar.y);
		}
		public static Rect ScalePosition(this Rect rect, Vector2 scalar)
		{
			return new Rect(rect.x * scalar.x, rect.y * scalar.y, rect.width, rect.height);
		}
		
		public static Rect Scale(this Rect rect, float xScale, float yScale)
		{
			return new Rect(rect.x * xScale, rect.y * yScale, rect.width * xScale, rect.height * yScale);
		}
		public static Rect ScaleSize(this Rect rect, float xScale, float yScale)
		{
			return new Rect(rect.x, rect.y, rect.width * xScale, rect.height * yScale);
		}
		public static Rect ScalePosition(this Rect rect, float xScale, float yScale)
		{
			return new Rect(rect.x * xScale, rect.y * yScale, rect.width, rect.height);
		}
		
		#endregion
		
		#region FROM
		public static Rect From(this Rect rect, Rect container)
		{
			return new Rect
			(
				container.x + rect.x * container.width,
				container.y + rect.y * container.height,
				rect.width * container.width, 
				rect.height * container.height
			);
		}
		public static Rect From(this Rect rect, Vector2 containerScale, Vector2 containerPosition)
		{
			return new Rect
			(
				containerPosition.x + rect.x * containerScale.x,
				containerPosition.y + rect.y * containerScale.y,
				rect.width * containerScale.x, 
				rect.height * containerScale.y
			);
		}
		public static Rect From(this Rect rect, Rect container, TextAnchor anchor)
		{
			return (rect.FromAnchor(anchor)).From(container.ToAnchor(anchor));
		}
		public static Rect From(this Rect rect, Vector2 containerScale, Vector2 containerPosition, TextAnchor anchor)
		{
			return rect.From(new Rect(containerPosition.x, containerPosition.y, containerScale.x, containerScale.y), anchor);
		}
		#endregion
		
		#region TO
		public static Rect To(this Rect rect, Rect container)
		{
			return new Rect
			(
				(rect.x / container.width) - container.x,
				(rect.y / container.height) - container.y,
				rect.width / container.width, 
				rect.height / container.height
			);
		}
		public static Rect To(this Rect rect, Vector2 containerScale, Vector2 containerPosition)
		{
			return new Rect
			(
				(rect.x / containerScale.x) - containerPosition.x,
				(rect.y / containerScale.y) - containerPosition.y,
				rect.width / containerScale.x, 
				rect.height / containerScale.y
			);
		}
		
		public static Rect To(this Rect rect, Rect container, TextAnchor anchor)
		{
			return rect.To(container.FromAnchor(anchor)).ToAnchor(anchor);
		}
		public static Rect To(this Rect rect, Vector2 containerScale, Vector2 containerPosition, TextAnchor anchor)
		{
			return rect.To(new Rect(containerPosition.x, containerPosition.y, containerScale.x, containerScale.y), anchor);
		}
		
		#endregion
		
		#region SPECIAL
		public static Rect InPixels(this Rect rect, TextAnchor anchor = TextAnchor.UpperLeft)
		{
			return rect.From(GetCamRect(), anchor);
		}
		public static Rect InScreenPixels(this Rect rect, TextAnchor anchor = TextAnchor.UpperLeft)
		{
			return rect.From(GetScreenRect(), anchor);
		}
		public static Rect ToCameraNormalSpace(this Rect rect, TextAnchor anchor = TextAnchor.UpperLeft)
		{
			return rect.To(GetCamRect(), anchor);
		}
		public static Rect ToScreenNormalSpace(this Rect rect, TextAnchor anchor = TextAnchor.UpperLeft)
		{
			return rect.To(GetScreenRect(), anchor);
		}
		
		#region GET
		private static Rect GetCamRect(TextAnchor anchor)
		{
			if(!Camera.current) return GetScreenRect(anchor);
			return Camera.current.pixelRect.ToAnchor(anchor);
		}
		private static Rect GetScreenRect(TextAnchor anchor)
		{
			return new Rect(0F, 0F, Screen.width, Screen.height).ToAnchor(anchor);
		}
		private static Rect GetCamRect()
		{
			if(!Camera.current) return GetScreenRect();
			return Camera.current.pixelRect;
		}
		private static Rect GetScreenRect()
		{
			return new Rect(0F, 0F, Screen.width, Screen.height);
		}
		#endregion
		
		#endregion
		
		#region ANCHOR
		public static Rect ToAnchor(this Rect rect, TextAnchor toAnchor)
		{
			if(toAnchor == TextAnchor.UpperLeft) return rect;
			
			Vector2 pos = GetAnchor(toAnchor);
			rect.x += pos.x * rect.width;
			rect.y += pos.y * rect.height;
			return rect;
		}
		public static Rect ToAnchor(this Rect rect, TextAnchor fromAnchor, TextAnchor toAnchor)
		{
			if(toAnchor == TextAnchor.UpperLeft) return rect.FromAnchor(fromAnchor);
			if(fromAnchor == TextAnchor.UpperLeft) return rect.ToAnchor(toAnchor);
			
			Vector2 pos = GetAnchor(toAnchor) - GetAnchor(fromAnchor);
			rect.x += pos.x * rect.width;
			rect.y += pos.y * rect.height;
			return rect;
		}
		public static Rect FromAnchor(this Rect rect, TextAnchor fromAnchor)
		{
			if(fromAnchor == TextAnchor.UpperLeft) return rect;
			
			Vector2 pos = GetAnchor(fromAnchor);
			rect.x -= pos.x * rect.width;
			rect.y -= pos.y * rect.height;
			return rect;
		}
		private static Vector2 GetAnchor(TextAnchor anchor)
		{
			Vector2 pos = Vector2.zero;
			switch(anchor)
			{
				case TextAnchor.LowerCenter:	pos = new Vector2(0.5F, 1.0F); break;
				case TextAnchor.LowerLeft:		pos = new Vector2(0.0F, 1.0F); break;
				case TextAnchor.LowerRight:		pos = new Vector2(1.0F, 1.0F); break;

				case TextAnchor.MiddleCenter:	pos = new Vector2(0.5F, 0.5F); break;
				case TextAnchor.MiddleLeft:		pos = new Vector2(0.0F, 0.5F); break;
				case TextAnchor.MiddleRight:	pos = new Vector2(1.0F, 0.5F); break;

				case TextAnchor.UpperCenter:	pos = new Vector2(0.5F, 0.0F); break;
				case TextAnchor.UpperLeft:		pos = new Vector2(0.0F, 0.0F); break;
				case TextAnchor.UpperRight:		pos = new Vector2(1.0F, 0.0F); break;
			}
			return pos;
		}
		#endregion
		
		#region OFFSET
		
		public static Rect Offset(this Rect rect, Vector2 offset)
		{
			rect.center += offset;
			return rect;
		}
		
		#endregion
	}
}

